
use std::fs::OpenOptions;
use std::io;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::thread;
use std::time::Duration;

// Ensure `libc` crate is added to `Cargo.toml` under `[dependencies]`
extern crate libc;

struct MemoryMap {
    ptr: *mut u8,
    len: usize,
}

impl MemoryMap {
    fn new(fd: i32, len: usize) -> io::Result<Self> {
        let ptr = unsafe {
            libc::mmap(
                std::ptr::null_mut(),
                len,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                fd,
                0,
            )
        };
        if ptr == libc::MAP_FAILED {
            Err(io::Error::last_os_error())
        } else {
            Ok(MemoryMap {
                ptr: ptr as *mut u8,
                len,
            })
        }
    }

    unsafe fn as_slice(&self) -> &[u8] {
        std::slice::from_raw_parts(self.ptr, self.len)
    }
}

impl Drop for MemoryMap {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.ptr as *mut libc::c_void, self.len);
        }
    }
}

fn main() -> io::Result<()> {
    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .mode(0o664)
        .open("temp")?;

    file.set_len(4096)?;

    let len = file.metadata()?.len() as usize;

    let memory_map = MemoryMap::new(file.as_raw_fd(), len)?;

    loop {
        thread::sleep(Duration::from_secs(1));

        let data_slice = unsafe { memory_map.as_slice() };
        // Ensure we do not exceed the bounds of the memory slice
        if data_slice.len() > 1024 {
            let message_slice = &data_slice[1024..];
            let rust_str = std::str::from_utf8(message_slice).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
            println!("{}", rust_str);
        }
    }
}
